package com.zx.idc.backend.gui.shiro;

import com.zx.idc.common.util.ProcessUtil;
import com.zx.idc.common.util.TimeConversionUtils;
import com.zx.idc.ds.sys.entity.SysUser;
import com.zx.idc.ds.sys.service.ISysUserService;
import com.zx.idc.ds.tlog.entity.TLogSecurity;
import com.zx.idc.ds.tlog.service.ITLogSecurityService;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.SessionListener;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

@Component
public class ShiroSessionListener implements SessionListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(ShiroSessionListener.class);

    @Autowired
    private ITLogSecurityService tlogSecurityService;
    @Autowired
    private ISysUserService sysUserService;

    /**
     * Notification callback that occurs when the corresponding Session has started.
     *
     * @param session the session that has started.
     */
    @Override
    public void onStart(Session session) {

    }

    /**
     * Notification callback that occurs when the corresponding Session has stopped, either programmatically via
     * {@link Session#stop} or automatically upon a subject logging out.
     *
     * @param session the session that has stopped.
     */
    @Override
    public void onStop(Session session) {

    }

    /**
     * Notification callback that occurs when the corresponding Session has expired.
     * <p/>
     * <b>Note</b>: this method is almost never called at the exact instant that the {@code Session} expires.  Almost all
     * session management systems, including Shiro's implementations, lazily validate sessions - either when they
     * are accessed or during a regular validation interval.  It would be too resource intensive to monitor every
     * single session instance to know the exact instant it expires.
     * <p/>
     * If you need to perform time-based logic when a session expires, it is best to write it based on the
     * session's {@link Session#getLastAccessTime() lastAccessTime} and <em>not</em> the time
     * when this method is called.
     *
     * @param session the session that has expired.
     */
    @Override
    public void onExpiration(Session session) {
        Object attribute = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
        if (attribute != null) {
            SysUser user = (SysUser) ((SimplePrincipalCollection) attribute).getPrimaryPrincipal();
            sysUserService.updateById(new SysUser().setId(user.getId()).setLastLoginTime(LocalDateTime.now()));
            tlogSecurityService.insert(new TLogSecurity(TLogSecurity.LOGOUT, user.getId(), session.getHost(), TimeConversionUtils.date2LocalDateTime(session.getLastAccessTime()), "用户登出", "登出成功", ProcessUtil.getPid(), null));
        }
    }
}
